defineClass('for', Virtual, function (base) {



    // 循环目标集合
    // 可以是数组模型也可以是普通的数组, 如果是普通数组不支持双向绑定
    defineProperty(this, 'each', {

        defaultValue: null,

        onchange: function (value, oldValue) {

            if (oldValue && oldValue instanceof DataModel)
            {
                unsubscribable(this, oldValue);
            }

            if (value && value instanceof DataModel)
            {
                subscribe(this, value);
            }

            onPropertyChanged.call(this);
        }
    });



    // 循环起始值
    defineProperty(this, 'from', {

        defaultValue: 1,
        onchange: onPropertyChanged
    });


    // 循环终止值
    defineProperty(this, 'to', {

        defaultValue: 1,
        onchange: onPropertyChanged
    });


    // 循环步长
    defineProperty(this, 'step', {

        defaultValue: 1,
        onchange: onPropertyChanged,

        convert: function (value) {

            return (value = +value) > 0 ? value : 1;
        }
    });



    function onPropertyChanged() {

        if (!this.__dirty)
        {
            var children = this.__children;

            if (children[0])
            {
                clearChildren(this, children);
            }

            this.__dirty = 1;
            invalidateVirtualObject.call(this);
        }
    }



    // 清除子项
    function clearChildren(vfor, children) {

        for (var i = children.length; i--;)
        {
            children[i].parent = null;
        }

        // 标记有移除子项
        vfor.__removed = 1;

        children.length = 0;
    }


    function updateReindex(vfor, index) {

        var reindex = vfor.__reindex;

        if (reindex < 0 || reindex > index)
        {
            vfor.__reindex = index;
        }
    }


    function loadRangeChildren(vfor, templateFn) {

        var build = buildObjectFromArray;
        var children = vfor.__children;
        var from = vfor.from;
        var to = vfor.to;
        var step = vfor.step;
        var object;

        if (from <= to)
        {
            while (from <= to)
            {
                if (object = build(vfor, templateFn(from)))
                {
                    children.push(object);
                }
    
                from += step;
            }
        }
        else
        {
            while (from >= to)
            {
                if (object = build(vfor, templateFn(from)))
                {
                    children.push(object);
                }

                from -= step;
            }
        }
    }


    function loadEachChildren(vfor, data, templateFn) {

        var children = vfor.__children;

        // 循环函数有两个参数时才创建index
        var Index = templateFn.length > 1 ? ValueState : null;
        var build = buildObjectFromArray;
        var length = data.length;
        var state, object;

        for (var i = 0; i < length; i++)
        {
            if (Index)
            {
                state = new Index(i);
            }

            if (object = build(vfor, templateFn(data[i], state)))
            {
                if (state)
                {
                    object.__for = state;
                }

                children.push(object);
            }
        }
    }



    function buildEachChildObject(vfor, item, index, templateFn) {

        var state, object;

        // 循环函数有两个参数时才创建index
        if (templateFn.length > 1)
        {
            state = new ValueState(index);
        }

        if (object = buildObjectFromArray(vfor, templateFn(item, state)))
        {
            object.__for = state;
            return object;
        }
    }


    // 订阅
    function subscribe(vfor, dataModel) {

        var dependences;

        if (dependences = dataModel.__deps)
        {
            for (var i = dependences.length; i--;)
            {
                if (dependences[i] === vfor)
                {
                    return;
                }
            }

            dependences.push(vfor);
        }
        else
        {
            dataModel.__deps = [vfor];
        }
    }


    // 取消订阅
    function unsubscribable(vfor, dataModel) {

        var dependences;

        if (dependences = dataModel.__deps)
        {
            for (var i = dependences.length; i--;)
            {
                if (dependences[i] === vfor)
                {
                    dependences.splice(i, 1);
                    break;
                }
            }
        }
    }



    this.__load = loadVirtuallDelay;



    this.getVisualObjects = function (outputs, destroyObjectFn) {

        var children = this.__children;
        var last, index, any;

        // 销毁移除的子项
        if (this.__removed)
        {
            this.__removed = 0;

            if (last = this.__last)
            {
                for (var i = last.length; i--;)
                {
                    if (!last[i].parent)
                    {
                        destroyObjectFn(last[i]);
                    }
                }
            }
        }

        // 需要重新构建子项集合
        if (this.__dirty)
        {
            this.__dirty = 0;

            if (any = this.__template)
            {
                if (last = this.each)
                {
                    loadEachChildren(this, last.$list || last, any);
                }
                else
                {
                    loadRangeChildren(this, any);
                }
            }
        }

        // 记录这次处理的子项集合作为后述移除用
        this.__last = children.slice(0);

        // 更新索引
        if ((index = this.__reindex) >= 0)
        {
            this.__reindex = -1;

            while (any = children[index])
            {
                any.__for.value = index++;
            }
        }

        // 输出非虚拟对象集合
        index = 0;

        while (any = children[index++])
        {
            if (any.__virtual)
            {
                any.getVisualObjects(outputs, destroyObjectFn);
            }
            else
            {
                outputs.push(any);
            }
        }
    }



    this.$onchange = function (type, arg1, arg2) {

        var templateFn, children;
        
        if (templateFn = this.__template)
        {
            children = this.__children;

            switch (type)
            {
                case 'load':
                case 'sort':
                    this.__dirty = 1;
                                
                    // 清除原子项
                    if (children[0])
                    {
                        clearChildren(this, children);
                    }
                    break;

                case 'set':
                    if (children.length > arg1)
                    {
                        children[arg1].parent = null;
                        children[arg1] = buildObjectFromArray(this, templateFn(arg2));
                    }
                    break;
    
                case 'insert':
                    if (arg1 >= 0)
                    {
                        if (arg2 = buildEachChildObject(this, arg2, arg1, templateFn))
                        {
                            children.splice(arg1, 0, arg2);
                            updateReindex(this, arg1);
                        }
                    }
                    else if (arg2 = buildEachChildObject(this, arg2, children.length, templateFn))
                    {
                        children.push(arg2);
                    }
                    break;
    
                case 'remove':
                    if (arg2 = children.splice(arg1, 1))
                    {
                        // 标记有移除子项
                        this.__removed = 1;

                        arg2[0].parent = null;
                        updateReindex(this, arg1);
                    }
                    break;
    
                case 'clear':
                    if (children[0])
                    {
                        clearChildren(this, children);
                    }
                    break;
    
                case 'reverse':
                    children.reverse();
                    updateReindex(this, 0);
                    break;
    
                default:
                    return;
            }

            // 通知父对象子集合已经发生变更
            invalidateVirtualObject.call(this);
        }
    }



    this.destroy = function () {

        var each = this.each;

        if (each && each instanceof DataModel)
        {
            unsubscribable(this, each);
        }

        base.destroy.call(this);
    }



}, function For() {

    this.__last = null;
    this.__dirty = 1;
    this.__removed = 0;
    this.__reindex = -1;

    this.init();
});
